use axum::extract::{Query, State};
use axum::http::{HeaderMap, StatusCode};
use axum::response::Response as AxumResponse;
use axum::routing::{get, post, put, delete};
use axum::{Router, body::Bytes};
use rustcloud_core::{Request, Response as ServiceResponse};
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info};

/// HTTP服务器状态
#[derive(Clone)]
pub struct ServerState {
    pub handlers: Arc<RwLock<HashMap<String, Box<dyn ServiceHandler + Send + Sync>>>>,
}

impl ServerState {
    pub fn new() -> Self {
        Self {
            handlers: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub async fn register_handler(
        &self,
        path: String,
        handler: Box<dyn ServiceHandler + Send + Sync>,
    ) {
        let mut handlers = self.handlers.write().await;
        handlers.insert(path.clone(), handler);
        info!("Registered handler for path: {}", path);
    }

    pub async fn unregister_handler(&self, path: &str) -> bool {
        let mut handlers = self.handlers.write().await;
        handlers.remove(path).is_some()
    }
}

#[derive(Deserialize)]
struct QueryParams {
    service_name: Option<String>,
    _method: Option<String>,
}


/// 服务处理器trait
#[async_trait::async_trait]
pub trait ServiceHandler: Send + Sync {
    async fn handle(&self, request: Request) -> ServiceResponse;
}

/// 简单的路由处理器
pub struct RouteHandler<F, Fut>
where
    F: Fn(Request) -> Fut + Send + Sync + 'static,
    Fut: std::future::Future<Output = ServiceResponse> + Send,
{
    handler: F,
}

impl<F, Fut> RouteHandler<F, Fut>
where
    F: Fn(Request) -> Fut + Send + Sync + 'static,
    Fut: std::future::Future<Output = ServiceResponse> + Send,
{
    pub fn new(handler: F) -> Self {
        Self { handler }
    }
}

#[async_trait::async_trait]
impl<F, Fut> ServiceHandler for RouteHandler<F, Fut>
where
    F: Fn(Request) -> Fut + Send + Sync + 'static,
    Fut: std::future::Future<Output = ServiceResponse> + Send,
{
    async fn handle(&self, request: Request) -> ServiceResponse {
        (self.handler)(request).await
    }
}

/// HTTP服务器
pub struct HttpServer {
    router: Router,
    state: ServerState,
}

impl HttpServer {
    pub fn new() -> Self {
        let state = ServerState::new();
        let router = Self::create_router(state.clone());
        
        Self { router, state }
    }

    fn create_router(state: ServerState) -> Router {
        Router::new()
            .route("/health", get(handle_health_check))
            .route("/info", get(handle_info))
            .route("/*path", get(handle_get))
            .route("/*path", post(handle_post))
            .route("/*path", put(handle_put))
            .route("/*path", delete(handle_delete))
            .with_state(state)
    }

    pub fn router(&self) -> Router {
        self.router.clone()
    }

    pub fn state(&self) -> ServerState {
        self.state.clone()
    }

    pub async fn register_route<F, Fut>(
        &self,
        path: impl Into<String>,
        handler: F,
    ) where
        F: Fn(Request) -> Fut + Send + Sync + 'static,
        Fut: std::future::Future<Output = ServiceResponse> + Send + 'static,
    {
        let path = path.into();
        let handler = Box::new(RouteHandler::new(handler));
        self.state.register_handler(path, handler).await;
    }
}

async fn handle_health_check() -> impl axum::response::IntoResponse {
    (StatusCode::OK, "healthy")
}

async fn handle_info(State(state): State<ServerState>) -> axum::Json<serde_json::Value> {
    let handlers = state.handlers.read().await;
    let paths: Vec<String> = handlers.keys().cloned().collect();
    
    axum::Json(serde_json::json!({
        "service": "rustcloud-transport",
        "version": env!("CARGO_PKG_VERSION"),
        "registered_paths": paths,
        "uptime": chrono::Utc::now().to_rfc3339(),
    }))
}

async fn handle_get(
    State(state): State<ServerState>,
    axum::extract::Path(path): axum::extract::Path<String>,
    headers: HeaderMap,
    query: Query<QueryParams>,
) -> Result<AxumResponse, StatusCode> {
    handle_request(state, path, headers, query.0, None, "GET".to_string()).await
}

async fn handle_post(
    State(state): State<ServerState>,
    axum::extract::Path(path): axum::extract::Path<String>,
    headers: HeaderMap,
    query: Query<QueryParams>,
    body: Bytes,
) -> Result<AxumResponse, StatusCode> {
    handle_request(state, path, headers, query.0, Some(body), "POST".to_string()).await
}

async fn handle_put(
    State(state): State<ServerState>,
    axum::extract::Path(path): axum::extract::Path<String>,
    headers: HeaderMap,
    query: Query<QueryParams>,
    body: Bytes,
) -> Result<AxumResponse, StatusCode> {
    handle_request(state, path, headers, query.0, Some(body), "PUT".to_string()).await
}

async fn handle_delete(
    State(state): State<ServerState>,
    axum::extract::Path(path): axum::extract::Path<String>,
    headers: HeaderMap,
    query: Query<QueryParams>,
) -> Result<AxumResponse, StatusCode> {
    handle_request(state, path, headers, query.0, None, "DELETE".to_string()).await
}

async fn handle_request(
    state: ServerState,
    path: String,
    headers: HeaderMap,
    query: QueryParams,
    body: Option<Bytes>,
    method: String,
) -> Result<AxumResponse, StatusCode> {
    let handlers = state.handlers.read().await;
    let handler = handlers.get(&format!("/{}", path.trim_start_matches('/')))
        .or_else(|| handlers.get(&path))
        .ok_or(StatusCode::NOT_FOUND)?;

    let mut request_headers = HashMap::new();
    for (key, value) in headers.iter() {
        request_headers.insert(key.to_string(), value.to_str().unwrap_or("").to_string());
    }

    let mut request = Request::new(
        query.service_name.unwrap_or_else(|| "default".to_string()),
        method,
        format!("/{}", path.trim_start_matches('/')),
    );

    request.headers = request_headers;

    if let Some(body) = body {
        request.set_body(body.to_vec());
    }

    let response = handler.handle(request).await;
    let mut axum_response = AxumResponse::builder();
    axum_response = axum_response.status(response.status);
    
    for (key, value) in response.headers {
        if let Ok(header_name) = axum::http::HeaderName::from_bytes(key.as_bytes()) {
            if let Ok(header_value) = axum::http::HeaderValue::from_str(&value) {
                axum_response = axum_response.header(header_name, header_value);
            }
        }
    }

    let body = response.body.unwrap_or_default();
    Ok(axum_response.body(axum::body::Body::from(body)).unwrap())
}

#[cfg(test)]
mod tests {
    use super::*;
    use tower::ServiceExt;
    use axum::http::StatusCode;
    use rustcloud_core::Response as ServiceResponse;

    #[tokio::test]
    async fn test_http_server_health_check() {
        let server = HttpServer::new();
        let router = server.router();
        let response = router
            .oneshot(axum::http::Request::builder()
                .uri("/health")
                .body(axum::body::Body::empty())
                .unwrap())
            .await
            .unwrap();
        
        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_http_server_route_registration() {
        let server = HttpServer::new();
        
        server.register_route("/test", |_request| async move {
            ServiceResponse::new(200)
        }).await;

        let router = server.router();
        let response = router
            .oneshot(axum::http::Request::builder()
                .uri("/test")
                .body(axum::body::Body::empty())
                .unwrap())
            .await
            .unwrap();
        
        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_http_server_not_found() {
        let server = HttpServer::new();
        let router = server.router();
        let response = router
            .oneshot(axum::http::Request::builder()
                .uri("/nonexistent")
                .body(axum::body::Body::empty())
                .unwrap())
            .await
            .unwrap();
        
        assert_eq!(response.status(), StatusCode::NOT_FOUND);
    }
}